#!/bin/dash

#Copyright (c) 2014 Luigi Tarenga <luigi.tarenga@gmail.com>
#Distributed under the terms of a MIT license.

case $1 in
get|list)
   #the get function try to always return something. if you need to be
   #sure that the leader is not stale you should commit a noop before calling get
   read last_log_index   < state/last_log_index
   read last_log_applied < temp/last_log_applied
   read quorum_heartbeat < temp/quorum_heartbeat
   if [ "$quorum_heartbeat" = "true" -a "$last_log_applied" -eq "$last_log_index" ] ; then
      #leader is not stale and everything is applied
      if [ -n "$2" ] ; then
         if [ "$1" = "get" ] ; then
            if [ -f state-machine-data/"$2" ] ; then
               read val < state-machine-data/"$2"
               echo $val
            else
               echo key "$2" does not exit. >&2
               exit 9
            fi
         else
            if [ -d state-machine-data/"$2" ] ; then
               ls -1 state-machine-data/"$2"
            else
               echo directory "$2" does not exit. >&2
               exit 8
            fi
         fi
      else
         echo null
      fi
   else
      echo leader is stale. try again. >&2
      exit 1
   fi
;;
if|set|unset|noop|conf_old_new|conf_new)
   read hostname         < temp/hostname
   read server_role      < temp/server_role
   read current_term     < state/current_term
   read last_log_index   < state/last_log_index
   read commit_index     < temp/commit_index

   if [ -d state-machine-log/"$last_log_index" ] ; then
      last_log_term=$(echo state-machine-log/"$last_log_index"/*)
      last_log_term=${last_log_term##state-machine-log/*/}
   else
      read last_log_term < state-machine-snapshot/cur/last_included_term
   fi

   if [ "$server_role" = "leader" ] ; then
      if [ "$1" = "if" -a "$5" = "set" ] ; then
         #this is a conditional set, check if key has the required value
         read last_log_applied < temp/last_log_applied
         read quorum_heartbeat < temp/quorum_heartbeat
         if [ "$quorum_heartbeat" = "true" -a "$last_log_applied" -eq "$last_log_index" ] ; then
            if [ -f state-machine-data/"$2" ] ; then
               read val < state-machine-data/"$2"
               if [ "$val" "$3" "$4" ] ; then
                  if [ "$val" = "$6" ] ; then
                     echo value of "$2" already set to "$6" >&2
                     exit 5
                  fi
                  #change positional parameter to perform a normal "set" in append-entry below
                  set -- "set" "$2" "$6"
               else
                  echo value of "$2" does not match "$4" >&2
                  exit 6
               fi
            else
               echo key "$2" does not exist. >&2
               exit 7
            fi
         else
            echo leader is stale. try again. >&2
            exit 1
         fi
      fi

      if [ "$1" = "conf_old_new" ] ; then
         for h in $2 ; do
            [ "$h" = "$hostname" ] && continue
            [ -f temp/${h}_next_index  ] && continue
            echo $((last_log_index+1)) > temp/${h}_next_index
            echo 0                      > temp/${h}_match_index
            echo 1                      > temp/${h}_follower_heartbeat
         done
      fi

      internals/append-entry $current_term $hostname $last_log_index $last_log_term \
         $current_term "$1" "$2 $3" $commit_index > temp/${hostname}_append_result
      read term result < temp/${hostname}_append_result

      if [ "$term" -eq "$current_term" -a "$result" = "true" ] ; then
         #append entry returned ok, now try to commit the change
         entry_index=$((last_log_index+1))
         internals/leader
         read commit_index < temp/commit_index

         if [ "$commit_index" -ge "$entry_index" -a -f state-machine-log/$entry_index/$term ] ; then
            #echo client succeded >&2
            :
         else
            echo timeout waiting for commit. >&2
            exit 2
         fi

      else
         echo append-entry failed. >&2
         exit 3
      fi
   else
      echo $hostname not leader. >&2
      exit 4
   fi
;;
esac
